<?php

namespace app\api\controller;

use think\Controller;
use think\Db;
use \Imagick;
use app\common\service\PdfOcrService;
use app\common\service\DoubleLayeredPdfService;
use app\common\helper\MyHelper;
use app\common\service\PackCompressService;
use app\admin\service\EsService;


class Ocrrecognition extends Controller


{
    // 默认图片分辨率（DPI）
    const DEFAULT_RESOLUTION = 300;
    // 标准A4页面尺寸（300DPI下）
    const PAGE_WIDTH = 2480;
    const PAGE_HEIGHT = 3508;
    // 文章状态常量
    const STATUS_PROCESSING = 2;
    const STATUS_COMPLETED = 1;
    const STATUS_ABNORMAL = 3;

    private $ip = "";
    private $time = 0;
    /**
     * 主处理入口
     *
     * @return \think\response\Json
     */

    public function index()
    {

   
        $ocrid = $_GET['ocrId'];

        $resOcr = Db::table('zstp_conf_ocr')->where(array('id' => $ocrid))->find();

        $this->ip=$resOcr['ip'];
     
    
        // try {
            // 获取未处理的任务
            $task = $this->getActiveTask();
            var_dump($task);
            // die();
            if (empty($task)) {
                sleep(10);
                return json(['code' => 0, 'msg' => '任务已经跑完']);
            }

            // 获取文章数据
            // $article = $this->getArticle($task['id']);

            // $map = [
            //     'task_id' => $task['id'],
            //     'ocr_status' => 0,
            //     //  "id"=>52
            // ];

            $map['id']=155;

             $time1 = time();

            Db::startTrans();
    
             $article  = Db::table('zstp_article_ocr')->where($map)->order('id', 'asc')->find();
             
          
           
             $douDir = $task['id'];

          
             
            if (empty($article)) {
               
                $this->updateTaskStatus($task['id'], self::STATUS_COMPLETED);
                Db::commit();
                return json(['code' => 0, 'msg' => '文章数据为空']);
            }
           
            $mapU['id']=array("=",$article['id']);
            $mapU['ocr_status']=array("=",0);

            $upd =   Db::table('zstp_article_ocr')->where($mapU)->update(['ocr_status' => 2]);

            if($upd > 0){
                Db::commit();
            }else{
                Db::rollback();
                return json(['code' => 0, 'msg' => '队列已经跑完']);
            }

            // 获取图片文件路径和列表
            $pathFolder = $this->getPathFolder($task, $article);

         
         
            $fileList = $this->getFileList($pathFolder, $article['jh']);


            if (empty($fileList)) {
                $error = "未找到符合卷号 {$article['jh']} 的文件";
                $this->updateArticleStatus($article['id'], 3 , $error);
                return json(['code' => 0, 'msg' => '未找到符合卷号的图片文件']);
            }

            // 确保PDF目录存在
            $pdfDirBase = $this->ensurePdfDirectory($article['id']);

            // 合成PDF
            $pdfPath = $this->convertMultipleTifsIntoOnePdf($fileList, $pathFolder, $article['id']);
    




            if (!file_exists($pdfPath)) {
                $error = "PDF文件不存在: " . $pdfPath;

                $this->updateArticleStatus($article['id'], 3, $error);
                return json(['code' => -1, 'msg' => 'PDF文件生成失败']);
            }

            // 处理OCR和生成双层PDF


            $result = $this->processOcr($pdfPath, $article, $douDir);




            if (!$result) {
                $this->updateArticleStatus($article['id'], 2, "合成双层pdf失败");
                return "合成双层pdf失败";
            }

            $time2 = time();
            $this->time = $time2 - $time1;
         
            //成功
            $this->updateArticleStatus($article['id'], 1);
        // } catch (\Exception $e) {
        //     error_log('OCR处理异常: ' . $e->getMessage());
        //     return json(['code' => -1, 'msg' => '处理异常: ' . $e->getMessage()]);
        // }
    }

    /**
     * 获取活动任务
     *
     * @return array|null
     */
    private function getActiveTask()
    {
        $mapTask = [
            // 'status' => 0,
            // 'is_delete' => 0
            "id"=>9
        ];

        return Db::table('zstp_article_task')->where($mapTask)->find();
    }

    /**
     * 更新任务状态
     *
     * @param int $taskId
     * @param int $status
     * @return bool
     */
    private function updateTaskStatus($taskId, $status)
    {

      
        return Db::table('zstp_article_task')->where('id', $taskId)->update(['status' => $status]);
    }

    /**
     * 更新文章状态
     *
     * @param int $articleId
     * @param int $status
     * @return bool
     */
    private function updateArticleStatus($articleId, $status, $error = "")
    {
        return Db::table('zstp_article_ocr')->where('id', $articleId)->update([
            'ocr_status' => $status,
            "error_log" => $error ,
            "ip"=> $this->ip,
            "running_time"=> $this->time
        ]);
    }

    /**
     * 获取文件夹完整路径
     *
     * @param array $task
     * @param array $article
     * @return string
     */
    private function getPathFolder($task, $article)
    {
        $pathName = $this->getDir($task);

        $folder = $this->SplicingFolder($article);

        return $pathName . $folder;
    }

    /**
     * 确保PDF目录存在
     *
     * @param int $articleId
     * @return string
     */
    private function ensurePdfDirectory($articleId)
    {
        $pdfDirBase = config("path") . "pdf/data/{$articleId}/";
        if (!file_exists($pdfDirBase)) {
            if (!mkdir($pdfDirBase, 0777, true)) {
                error_log("创建PDF目录失败: " . $pdfDirBase);
                throw new \Exception("无法创建PDF保存目录");
            }
            chmod($pdfDirBase, 0777);
        }
        return $pdfDirBase;
    }

    /**
     * 处理OCR和生成双层PDF
     *
     * @param string $pdfPath
     * @param array $article
     * @return bool
     */
    private function processOcr($pdfPath, $article, $douDir)
    {
        try {
            // 执行OCR识别
            $pdfOcrService = new PdfOcrService();

            $ip=$this->ip;

            $ocrResult = $pdfOcrService->ocrPdf($pdfPath ,$ip);

            if (empty($ocrResult['final_text_output'])) {
                error_log("OCR结果为空");
                return false;
            }

            // 处理OCR文本
            $content = processText($ocrResult['final_text_output'], $threshold = 0.2);

            // 保存JSON数据
            $jsonData = json_encode($ocrResult['results'], JSON_UNESCAPED_UNICODE);
            $jsonPath = $this->getUniqueString($article['id'], 3);
            file_put_contents($jsonPath, $jsonData);

            // 生成双层PDF
            $doublelayerPdfPath = config("path") . "pdf/data/{$article['id']}/" . "{$article['dh']}.pdf";



            $jsonData = json_decode($jsonData, true);

            $doubleLayeredPdfService = new DoubleLayeredPdfService();
            $pdfDoubleResult = $doubleLayeredPdfService->index($jsonPath, $pdfPath, $doublelayerPdfPath);
            var_dump(3333);
            var_dump($pdfDoubleResult);

            
            // 处理内容并更新数据库
            $textData = MyHelper::getArticleInfo($content);
        

            if (empty($textData['data'])) {
                $this->updateArticleStatus($article['id'], self::STATUS_ABNORMAL, "合成双层pdf失败");
                return "合成双层pdf失败";
            }
          
            Db::table("zstp_article_ocr")->where('id', $article['id'])->update(['content' => $textData['data']]);
            // 保存文本文件
            $txtPath = config("path") . "pdf/data/{$article['id']}/" . "{$article['dh']}.txt";
            file_put_contents($txtPath, $content);


            //生成xml
            $xml = $this->synthesizeXML($article);
        
            $xmlPath = config("path") . "pdf/data/{$article['id']}/" . "{$article['dh']}.xml";
            $xmlResult =   file_put_contents($xmlPath, $xml);
           
            
            // 打包处理
            $packCompressService = new PackCompressService();
            $packResult = $packCompressService->index($txtPath, $doublelayerPdfPath, $xmlPath, $article['qzh'], $article['lbh'], $article['dh'], $douDir);

            if ($packResult) {
                $this->updateArticleStatus($article['id'], self::STATUS_COMPLETED);


                $EsService = new  EsService();
                $EsService->addData($article['id'], $textData['data'], $article['dh']);
                return true;
            }

            return false;
        } catch (\Exception $e) {
            error_log("OCR处理异常: " . $e->getMessage());
            return false;
        }
    }





    /**
     * 图片合成PDF
     *
     * @param array $data 图片文件名数组
     * @param string $path 图片文件路径
     * @param int $id 文章ID
     * @return string PDF文件路径
     */
    function convertMultipleTifsIntoOnePdf($data, $path, $id)
    {
        // 设置内存限制
        $memoryLimit = 2048;
        $defaultResolution = self::DEFAULT_RESOLUTION;
        $standardWidth = self::PAGE_WIDTH;
        $standardHeight = self::PAGE_HEIGHT;

        var_dump("设置统一PDF页面尺寸: {$standardWidth} x {$standardHeight}, 分辨率: {$defaultResolution} DPI");
        var_dump("处理的图片数量: " . count($data));
        

        // 创建用于最终PDF的Imagick对象
        $finalPdf = new \Imagick();
        $finalPdf->setResourceLimit(\Imagick::RESOURCETYPE_MEMORY, $memoryLimit);
        $finalPdf->setResolution($defaultResolution, $defaultResolution);

        // 设置TIFF标签忽略选项
        $this->setImagickOptions($finalPdf);

        // 处理每张图片
        foreach ($data as $key => $value) {
            $file = $path . "/" . $value;
            error_log("处理图片: " . $file);

            try {
                $image = $this->processImage($file, $defaultResolution, $standardWidth, $standardHeight);
                $finalPdf->addImage($image);
                $image->clear();
                $image->destroy();
            } catch (\Exception $e) {
                error_log("处理图片失败: " . $file . " - " . $e->getMessage());
                continue;
            }
        }

        // 生成并保存PDF
        $pdPath = $this->getUniqueString($id);        
        $this->savePdf($finalPdf, $pdPath, $defaultResolution);

        // 清理资源
        $finalPdf->clear();
        $finalPdf->destroy();

        return $pdPath;
    }

    /**
     * 设置Imagick选项
     *
     * @param \Imagick $imagick
     */
    private function setImagickOptions(\Imagick $imagick)
    {
        $imagick->setOption('tiff:ignore-tags', '*');
        putenv('MAGICK_IGNORED_TAGS=329434');
        putenv('MAGICK_IGNORED_TAGS=32768-65535');
        putenv('MAGICK_IGNORED_TAGS=0-65535');
    }

    /**
     * 处理单个图片
     *
     * @param string $file
     * @param int $resolution
     * @param int $width
     * @param int $height
     * @return \Imagick
     */
    private function processImage($file, $resolution, $width, $height)
    {
        $image = new \Imagick();
        $image->setResolution($resolution, $resolution);
        $image->readImage($file);

        // 设置图像分辨率
        $image->setImageResolution($resolution, $resolution);

        // 调整图片大小
        $image->resizeImage($width, $height, \Imagick::FILTER_LANCZOS, 1, true);

        // 设置压缩方式
        $image->setImageCompression(\Imagick::COMPRESSION_JPEG);
        $image->setImageFormat('jpeg');

        // 设置DPI
        $image->setImageUnits(\Imagick::RESOLUTION_PIXELSPERINCH);
        $image->setImageResolution($resolution, $resolution);

        return $image;
    }

    /**
     * 保存PDF文件
     *
     * @param \Imagick $pdf
     * @param string $path
     * @param int $resolution
     */
    private function savePdf(\Imagick $pdf, $path, $resolution)
    {
        // 确保分辨率设置正确
        $pdf->setImageUnits(\Imagick::RESOLUTION_PIXELSPERINCH);
        $pdf->setImageResolution($resolution, $resolution);

        // 设置PDF选项
        $pdf->setImageFormat('pdf');
        $pdf->setOption('density', "{$resolution}x{$resolution}");
        $pdf->setOption('pdf:use-cropbox', 'true');
        $pdf->setOption('pdf:compression', 'flate');

        // 输出PDF页数用于调试
        error_log("PDF页数: " . $pdf->getNumberImages());

        // 保存PDF
        $pdf->writeImages($path, true);
    }

    /**
     * 获取唯一文件路径
     *
     * @param int $id
     * @param int $type
     * @return string
     */
    function getUniqueString($id, $type = 1)
    {
        // 保存为PDF文件
        $pdPath = config("path") . "pdf/data/{$id}/";
        // 检查目录是否存在
        if (!file_exists($pdPath)) {
            // 目录不存在，尝试创建 
            if (!mkdir($pdPath, 0777, true)) {
                error_log("创建目录失败: " . $pdPath);
                throw new \Exception("无法创建PDF保存目录");
            }
            // 确保权限正确
            chmod($pdPath, 0777);
            error_log("成功创建PDF目录: " . $pdPath);
        }

        $str = md5($id);

        if ($type == 1) {
            $pdPath = $pdPath . "{$str}_monolayer.pdf";
        } elseif ($type == 2) {
            $pdPath = $pdPath . "{$str}_double.pdf";
        } elseif ($type == 3) {
            $pdPath = $pdPath . "{$str}_data.json";
        }

        return $pdPath;
    }

    /**
     * 获取指定卷号的所有图片文件
     * 
     * @param string $pathFolder 文件夹路径
     * @param string $jh 卷号，如'001'或'120'
     * @return array 符合卷号的文件数组
     */
    function getFileList($pathFolder, $jh)
    {
     
        if (!file_exists($pathFolder)) {
            error_log("路径不存在: " . $pathFolder);
            if (!mkdir($pathFolder, 0777, true)) {
                throw new \Exception("无法创建路径: " . $pathFolder);
            }
            error_log("成功创建路径: " . $pathFolder);
            return []; // 新创建的目录肯定是空的
        }

        if (!is_readable($pathFolder)) {
            error_log("路径不可读: " . $pathFolder);
            throw new \Exception("无法读取路径: " . $pathFolder);
        }

        // 获取所有文件
        $allFiles = scandir($pathFolder);
        if ($allFiles === false) {
            error_log("无法扫描目录: " . $pathFolder);
            throw new \Exception("无法扫描目录: " . $pathFolder);
        }

        // 过滤掉隐藏文件和目录
        $filteredFiles = array_filter($allFiles, function ($file) {
            return $file[0] !== '.';
        });

        // 确保卷号是3位数格式
        $jhPadded = str_pad($jh, 3, '0', STR_PAD_LEFT);
        error_log("查找卷号: " . $jhPadded);

        // 过滤得到指定卷号的文件
        $result = [];
        foreach ($filteredFiles as $file) {
            // 确保文件名至少有3个字符
            if (strlen($file) >= 3) {
                // 检查文件名前3位是否匹配卷号
                if (substr($file, 0, 3) === $jhPadded) {
                    // 检查文件是否真的是文件而不是目录
                    $fullPath = $pathFolder . '/' . $file;
                    if (is_file($fullPath)) {
                        $result[] = $file;
                    }
                }
            }
        }

        error_log("找到卷号 " . $jhPadded . " 的文件数量: " . count($result));

        if (count($result) == 0) {
            error_log("未找到卷号 " . $jhPadded . " 的文件");
        }

        // 使用自然排序算法对文件名进行升序排序
        sort($result, SORT_NATURAL);

        return $result;
    }

    /**
     * 拼接文件夹路径
     *
     * @param array $Article 文章数据
     * @return string
     */
    function SplicingFolder($Article)
    {
        if (empty($Article) || !isset($Article['bgqx']) || !isset($Article['lbh']) || !isset($Article['ajh'])) {
            error_log("拼接文件夹失败: 文章数据不完整");
            throw new \Exception("文章数据不完整，无法拼接文件夹路径");
        }

        $bgqx = $Article['bgqx'];
        $folder = $bgqx . "WS.WS" . $Article['lbh'] . $Article['ajh'];
        error_log("拼接的文件夹路径: " . $folder);
        return $folder;
    }

    /**
     * 获取未处理的文章
     *
     * @param int $taskId
     * @return array|null
     */
    function getArticle($taskId)
    {

        //

       
    }

    /**
     * 获取文件夹路径
     *
     * @param string $dir
     * @return string
     */
    function getDir($task)
    {
        $finalDir = $task['path']."/";
        return $finalDir;
    }


    public function synthesizeXML($article)
    {

        //唯一标识
        $xml = '<?xml version="1.0" encoding="UTF-8"?><Root>';
        //密级
        $row = '<row SourceFieldName="mj" NewFieldName="密级" value="' . $article['mj'] . '"></row>';
        $xml = $xml . $row;
        //载体类型
        $row = '<row SourceFieldName="ztlx" NewFieldName="载体类型" value="' . $article['ztlx'] . '"></row>';
        $xml = $xml . $row;


        //文种
        $row = '<row SourceFieldName="wz" NewFieldName="文种" value="' . $article['wz'] . '"></row>';
        $xml = $xml . $row;

        //档案馆号
        $row = '<row SourceFieldName="dagdh" NewFieldName="档案管号" value="' . $article['dagdh'] . '"></row>';
        $xml = $xml . $row;

        //文件编号
        $row = '<row SourceFieldName="wjbh" NewFieldName="文件编号" value="' . $article['wjbh'] . '"></row>';
        $xml = $xml . $row;

        //微缩号
        $row = '<row SourceFieldName="swh" NewFieldName="微缩号" value="' . $article['swh'] . '"></row>';
        $xml = $xml . $row;


        //档号
        $row = '<row SourceFieldName="dh" NewFieldName="档号" value="' . $article['dh'] . '"></row>';
        $xml = $xml . $row;


        //全宗号
        $row = '<row SourceFieldName="qzh" NewFieldName="全宗号" value="' . $article['qzh'] . '"></row>';
        $xml = $xml . $row;

        //保管期限
        $row = '<row SourceFieldName="bgqx" NewFieldName="保管期限" value="' . $article['bgqx'] . '"></row>';
        $xml = $xml . $row;

        //类别号
        $row = '<row SourceFieldName="lbh" NewFieldName="类别号" value="' . $article['lbh'] . '"></row>';
        $xml = $xml . $row;


        //主题词
        $row = '<row SourceFieldName="ztc" NewFieldName="主题词" value="' . $article['ztc'] . '"></row>';
        $xml = $xml . $row;

        //案卷号
        $row = '<row SourceFieldName="ajh" NewFieldName="案卷号" value="' . $article['ajh'] . '"></row>';
        $xml = $xml . $row;

        //件号
        $row = '<row SourceFieldName="jh" NewFieldName="件号" value="' . $article['jh'] . '"></row>';
        $xml = $xml . $row;

        //子件号
        $row = '<row SourceFieldName="zjh" NewFieldName="子件号" value="' . $article['zjh'] . '"></row>';
        $xml = $xml . $row;

        //全文标识
        $row = '<row SourceFieldName="qwbs" NewFieldName="全文标识" value="' . $article['qwbs'] . '"></row>';
        $xml = $xml . $row;

        //题名
        $row = '<row SourceFieldName="tm" NewFieldName="题名" value="' . $article['tm'] . '"></row>';
        $xml = $xml . $row;

        //文种
        $row = '<row SourceFieldName="wb" NewFieldName="文种" value="' . $article['wb'] . '"></row>';
        $xml = $xml . $row;

        //责任者
        $row = '<row SourceFieldName="zrz" NewFieldName="责任者" value="' . $article['zrz'] . '"></row>';
        $xml = $xml . $row;

        //时间
        $row = '<row SourceFieldName="sj" NewFieldName="时间" value="' . $article['sj'] . '"></row>';
        $xml = $xml . $row;

        //载体数量
        $row = '<row SourceFieldName="ztsl" NewFieldName="载体数量" value="' . $article['ztsl'] . '"></row>';
        $xml = $xml . $row;


        //载体单位
        $row = '<row SourceFieldName="ztdw" NewFieldName="载体单位" value="' . $article['ztdw'] . '"></row>';
        $xml = $xml . $row;

        //载体规格
        $row = '<row SourceFieldName="ztgg" NewFieldName="载体规格" value="' . $article['ztgg'] . '"></row>';
        $xml = $xml . $row;

        //分类号
        $row = '<row SourceFieldName="flh" NewFieldName="分类号" value="' . $article['flh'] . '"></row>';
        $xml = $xml . $row;

        //主题词
        $row = '<row SourceFieldName="ztc" NewFieldName="主题词" value="' . $article['ztc'] . '"></row>';
        $xml = $xml . $row;

        //附注
        $row = '<row SourceFieldName="fz" NewFieldName="附注" value="' . $article['fz'] . '"></row>';
        $xml = $xml . $row;

        $xml = $xml . '</Root>';

        return $xml;
    }
    public function reprocessocrdocument()
    {

        $data = request()->put();
        $id = $data['id'];
        $article = Db::table('zstp_article_ocr')->where(array('id' => $id))->find();

        $task = Db::table('zstp_article_task')->where(array('id' => $article['task_id']))->find();

        $douDir = $task['id'];



        if (empty($article)) {
            $this->updateTaskStatus($task['id'], self::STATUS_COMPLETED);
            return json(['code' => 400, 'msg' => '文章数据为空']);
        }

        // 更新文章为处理中状态
        $this->updateArticleStatus($article['id'], 2);

        // 获取图片文件路径和列表
        $pathFolder = $this->getPathFolder($task, $article);



        $fileList = $this->getFileList($pathFolder, $article['jh']);
    
        if (empty($fileList)) {
            $error = "未找到符合卷号 {$article['jh']} 的文件";
            $this->updateArticleStatus($article['id'], 3, $error);
            return json(['code' => 400, 'msg' => '未找到符合卷号的图片文件']);
        }



        // 合成PDF
        $pdfPath = $this->convertMultipleTifsIntoOnePdf($fileList, $pathFolder, $article['id']);




        if (!file_exists($pdfPath)) {
            $error = "PDF文件不存在: " . $pdfPath;

            $this->updateArticleStatus($article['id'], 2, $error);

            return json(['code' => -400, 'msg' => 'PDF文件生成失败']);
        }

        // 处理OCR和生成双层PDF

        $mapOcr['is_delete']=array("=",0);

        $resOcr = Db::table('zstp_conf_ocr')->where($mapOcr)->find();

        $this->ip=$resOcr['ip']; 



        $result = $this->processOcr($pdfPath, $article, $douDir);


        if (!$result) {
            $this->updateArticleStatus($article['id'], 2, "合成双层pdf失败");
            return json(['code' => 400, 'msg' => '合成双层pdf失败']);
            return "合成双层pdf失败";
        }
        //成功
        $this->updateArticleStatus($article['id'], 1);



        ob_clean();


        return json(["code" => 200, "msg" => "处理成功"]);
    }


    public function getArticleList()
    {
        
        $path="/Users/woniu/工作/项目/档案馆/代码/njzstp_ocr_api/public/pdfpackaging/10/FZ02/1955/FZ02-Y-WS-W1955-001-001/FZ02-Y-WS-W1955-001-001.xml";
        $xml = simplexml_load_file($path);
        $json = json_encode($xml);
        $array = json_decode($json, true);
        var_dump($array);
    }


}
